import express from "express";
import fetch from 'node-fetch';
import { logger, saveBufferToLocal } from '../tools/index.js';
import NodeCache from 'node-cache';
const CACHE_EXPIRE_SECONDS = 3 * 60 * 60;
export async function createHook({ bindWxId, serverPort, callbackPort, onMessage }) {
    const app = express();
    // 缓存三个小时
    const wechatCache = new NodeCache({ stdTTL: CACHE_EXPIRE_SECONDS, checkperiod: CACHE_EXPIRE_SECONDS });

    app.use(express.json());
    app.post('/', (req, res) => {
        const callbackMsg = req.body.data;
        logger.info("Receiver wechat callback msg: %s", JSON.stringify(callbackMsg));
        if (callbackMsg.type === 'D0003') {
            onMessage(callbackMsg.data);
        }
        res.send('successful');
    });

    app.listen(callbackPort, () => {
        logger.info(`Wechat callback server is running on port ${callbackPort}`);
    });

    const post = async (type, data = {}) => {
        const serverUrl = `http://127.0.0.1:${serverPort}/DaenWxHook/httpapi/?wxid=${bindWxId}`;
        const myHeaders = new Headers();
        myHeaders.append("Content-Type", "application/json");
        const requestOptions = {
            method: 'POST',
            headers: myHeaders,
            body: JSON.stringify({ type, data }),
            redirect: 'follow'
        };

        try {
            const response = await fetch(serverUrl, requestOptions);
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }
            const res = await response.json();
            logger.info("Send msg to wechat server, type = %s, data = %s, resp = %s", type, JSON.stringify(data), JSON.stringify(res));
            if (res.code !== 200) {
                throw new Error(res.msg);
            }
            return res.result;
        } catch (error) {
            throw error;
        }
    }
    const getRooms = async (useCache = true) => {
        return post('Q0006', {
            type: useCache ? 1 : 2
        });
    };
    const getRoom = async (wxid) => {
        let rooms = await getRooms(true);
        let room = rooms.find(r => r.wxid === wxid);
        if (room) {
            return room;
        }
        rooms = await getRooms(false);
        return rooms.find(r => r.wxid === wxid);
    };
    const getFriends = async (useCache = true) => {
        return post('Q0005', {
            type: useCache ? 1 : 2
        });
    };
    const getFriend = async (wxId) => {
        let friends = await getFriends(true);
        let friend = friends.find(r => r.wxid === wxId);
        if (friend) {
            return friend;
        }
        friends = await getFriends(false);
        return friends.find(r => r.wxid === wxId);
    };
    const getRoomUsers = async (wxid) => {
        return await post('Q0008', {
            wxid: wxid
        });
    };
    const getUserRooms = async (wxid) => {
        const rooms = await getRooms();
        const userRooms = [];
        for (const room of rooms) {
            const users = await getRoomUsers(room.wxid);
            if (users.some(user => user.wxid === wxid)) {
                userRooms.push({
                    ...room,
                    users
                });
            }
        }
        return userRooms;
    };
    const getByCache = async (cacheKey, supplierFunc) => {
        const cacheValue = wechatCache.get(cacheKey);
        if (cacheValue) {
            return cacheValue;
        }
        
        const value = await supplierFunc();
        wechatCache.set(cacheKey, value, CACHE_EXPIRE_SECONDS);
        return value;
    }
    return {
        getCurrentUser: async () => {
            return post('Q0003');
        },
        getUser: async (wxId) => {
            return await post('Q0004', {
                wxid: wxId
            });
        },
        getRooms: getRooms,
        getFriends: getFriends,
        getRoom: getRoom,
        getFriend: getFriend,
        sendMessage: async (wxid, msg) => {
            return await post('Q0001', {
                "wxid": wxid,
                "msg": msg
            });
        },
        getRoomUsers: getRoomUsers,
        getUserRooms: async (wxid) => {
            return await getByCache(`wechat_rooms_${wxid}`, () => getUserRooms(wxid));
        },
        sendFile: async (wxid, fileName, fileBuffer) => {
            const filePath = await saveBufferToLocal(fileName, fileBuffer);
            return post('Q0011', {
                "wxid": wxid,
                "path": filePath
            });
        }
    }
}